home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 …ember: Reference Library / Apple Developer Reference Library (December 1999) (Disk 1).iso / pc / what's new / sample code / human interface toolbox / packagetool / packagewindow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-22  |  22.5 KB  |  674 lines

  1. /*
  2.     file PackageWindow.c
  3.     
  4.     Description:
  5.     This file contains the routines that implement the functionality
  6.     provided by the main window displayed by the PackageTool
  7.     application.
  8.     
  9.     PackageTool is an application illustrating how to create application
  10.     packages in Mac OS 9.  It provides a simple interface for converting
  11.     correctly formatted folders into packages and vice versa.
  12.  
  13.     by John Montbriand, 1999.
  14.  
  15.     Copyright: © 1999 by Apple Computer, Inc.
  16.     all rights reserved.
  17.     
  18.     Disclaimer:
  19.     You may incorporate this sample code into your applications without
  20.     restriction, though the sample code has been provided "AS IS" and the
  21.     responsibility for its operation is 100% yours.  However, what you are
  22.     not permitted to do is to redistribute the source as "DSC Sample Code"
  23.     after having made changes. If you're going to re-distribute the source,
  24.     we require that you make it clear in the source that the code was
  25.     descended from Apple Sample Code, but that you've made changes.
  26.     
  27.     Change History (most recent first):
  28.     10/19/99 created by John Montbriand
  29. */
  30.  
  31. #include "PackageWindow.h"
  32. #include "PackageTool.h"
  33. #include "PackageUtils.h"
  34. #include "Utilities.h"
  35. #include <Drag.h>
  36. #include <Controls.h>
  37. #include <Dialogs.h>
  38. #include <Appearance.h>
  39. #include <Icons.h>
  40. #include <string.h>
  41. #include <TextUtils.h>
  42.  
  43.  
  44.  
  45.  
  46.  
  47. enum {    /* picture displayed when selection is empty */
  48.     kSpashPictResource = 128
  49. };
  50.  
  51.     /* main window dialog constants */
  52. enum {
  53.     kPackageDialogResource = 128,
  54.     kPackageUserItem = 1,
  55.     kFolderItem = 2,
  56.     kPackageItem = 3,
  57.         /* kFolderIsPackage and kFolderIsFolder are used for
  58.         internal tracking of the state of the kFolderItem and
  59.         the kPackageItem dialog controls. */
  60.     kFolderIsPackage = 100,    /* item being displayed is a package */
  61.     kFolderIsFolder = 101    /* item being displayed is a folder */
  62. };
  63.  
  64.  
  65.     /* variables used to record properties of the main window */
  66. DialogPtr gPackageWindow = NULL; /* a pointer to the main dialog */
  67. PicHandle gSplashPict; /* splash image displayed in gIconBox when there is no file selected */
  68. Rect gIconBox; /* area in the window where the information about the current file is drawn */ 
  69. Rect gIconImage; /* area inside of gIconBox where the icon is drawn */
  70. ControlHandle gPackageButton; /* control for setting gFolderTypeSelection to kFolderIsPackage */
  71. ControlHandle gFolderButton; /* control for setting gFolderTypeSelection to kFolderIsFolder */
  72.  
  73.     /* variables used to record information about the file being displayed */
  74. Boolean gFileInDisplay = false; /* true when gFileAlias contains an alias handle */
  75. AliasHandle gFileAlias = NULL; /* an alias to the last file dragged into the gIconBox */
  76. IconRef gIconRef = NULL; /* an icon services reference to an icon for the file */
  77. short gFolderTypeSelection = kFolderIsFolder; /* determines the type of data we will provide for drags */
  78. Boolean gPWActive = false;
  79.  
  80.     /* these routines are used both in the receive handler and inside of the
  81.         tracking handler.  The following variables are shared between MyDragTrackingHandler
  82.         and MyDragReceiveHandler.  */
  83. static Boolean gApprovedDrag = false; /* set to true if the drag is approved */
  84. static Boolean gInIconBox = false; /* set true if the drag is inside our drop box */
  85.  
  86.     /* procedure pointers used in the main window */
  87. DragReceiveHandlerUPP gMainReceiveHandler = NULL; /* receive handler for the main dialog */
  88. DragTrackingHandlerUPP gMainTrackingHandler = NULL; /* tracking handler for the main dialog */
  89. UserItemUPP myUserItem; /* UPP for the icon's user item.  This routine draws into gIconBox */
  90.  
  91.  
  92. Boolean IsPackageWindow(WindowPtr target) {
  93.     return (target == gPackageWindow);
  94. }
  95.  
  96.  
  97. /* ApproveDragReference is called by the drag tracking handler to determine
  98.     if the contents of the drag can be handled by our receive handler.
  99.     here, we only allow packages and folders.  */
  100. static pascal OSErr ApproveDragReference(DragReference theDragRef, Boolean *approved) {
  101.     OSErr err;
  102.     UInt16 itemCount;
  103.     DragAttributes dragAttrs;
  104.     ItemReference theItem;
  105.     HFSFlavor targetFile;
  106.     long theSize;
  107.     
  108.         /* we cannot drag to our own window */
  109.     if ((err = GetDragAttributes(theDragRef, &dragAttrs)) != noErr) goto bail;
  110.     if ((dragAttrs & kDragInsideSenderWindow) != 0) { err = userCanceledErr; goto bail; }
  111.     
  112.         /* we only accept drags containing one item */
  113.     if ((err = CountDragItems(theDragRef, &itemCount)) != noErr) goto bail;
  114.     if (itemCount != 1) { err = paramErr; goto bail; }
  115.         
  116.         /* gather information about the drag & a reference to item one. */
  117.     if ((err = GetDragItemReferenceNumber(theDragRef, 1, &theItem)) != noErr) goto bail;
  118.         
  119.         /* try to get a  HFSFlavor*/
  120.     theSize = sizeof(HFSFlavor);
  121.     err = GetFlavorData(theDragRef, theItem, flavorTypeHFS, &targetFile, &theSize, 0);
  122.     if (err != noErr) goto bail;
  123.  
  124.         /* it must be a folder or a package */
  125.     if (IdentifyPackage(&targetFile.fileSpec, NULL))
  126.         *approved = true;
  127.     else if (targetFile.fileCreator == 'MACS' && targetFile.fileType == 'fold')
  128.         *approved = true;
  129.     else {
  130.         err = paramErr;
  131.         goto bail;
  132.     }
  133.                 
  134.     return noErr;
  135. bail:
  136.         /* an error occured, clean up.  set result to false. */
  137.     *approved = false;
  138.     return err;
  139. }
  140.  
  141.  
  142.  
  143.  
  144. /* MyDragTrackingHandler is called for tracking the mouse while a drag is passing over our
  145.     window.  if the drag is approved, then the drop box will be hilitied appropriately
  146.     as the mouse passes over it.  */
  147. static pascal OSErr MyDragTrackingHandler(DragTrackingMessage message, WindowPtr theWindow, void *refCon, DragReference theDragRef) {
  148.         /* we're drawing into the image well if we hilite... */
  149.     switch (message) {
  150.     
  151.         case kDragTrackingEnterWindow:
  152.             {    Point mouse;
  153.                 gApprovedDrag = false;
  154.                 if (theWindow == FrontWindow()) {
  155.                     if (ApproveDragReference(theDragRef, &gApprovedDrag) != noErr) break;
  156.                     if ( ! gApprovedDrag ) break;
  157.                     SetPort(theWindow);
  158.                     GetMouse(&mouse);
  159.                     if (PtInRect(mouse, &gIconBox)) {  /* if we're in the box, hilite... */
  160.                         SetPort(theWindow);
  161.                         gInIconBox = (ShowDragHiliteBox(theDragRef, &gIconBox) == noErr);
  162.                     }
  163.                 }
  164.             }
  165.             break;
  166.  
  167.         case kDragTrackingInWindow:
  168.             if (gApprovedDrag) {
  169.                 Point mouse;
  170.                 SetPort(theWindow);
  171.                 GetMouse(&mouse);
  172.                 if (PtInRect(mouse, &gIconBox)) {
  173.                     if ( ! gInIconBox) {  /* if we're entering the box, hilite... */
  174.                         SetPort(theWindow);
  175.                         gInIconBox = (ShowDragHiliteBox(theDragRef, &gIconBox) == noErr);
  176.                     }
  177.                 } else if (gInIconBox) {  /* if we're exiting the box, unhilite... */
  178.                     HideDragHilite(theDragRef);
  179.                     gInIconBox = false;
  180.                 }
  181.             }
  182.             break;
  183.  
  184.         case kDragTrackingLeaveWindow:
  185.             if (gApprovedDrag && gInIconBox) {
  186.                 HideDragHilite(theDragRef);
  187.             }
  188.             gApprovedDrag = gInIconBox = false;
  189.             break;
  190.     }
  191.     return noErr; // there's no point in confusing Drag Manager or its caller
  192. }
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199. /* MyDragReceiveHandler receives drags that are dropped into the
  200.     main window.  here, we only receive packages or folders. */
  201. static pascal OSErr MyDragReceiveHandler(WindowPtr theWindow, void *refcon, DragReference theDragRef) {
  202.     ItemReference theItem;
  203.     HFSFlavor targetFile;
  204.     Size theSize;
  205.     OSErr err;
  206.     
  207.         /* validate the drag.  Recall the receive handler will only be called after
  208.         the tracking handler has received a kDragTrackingInWindow event.  As a result,
  209.         the gApprovedDrag and gInIconBox will be defined when we arrive here.  Hence,
  210.         there is no need to spend extra time validating the drag at this point. */
  211.     if ( ! (gApprovedDrag && gInIconBox) ) { err = userCanceledErr; goto bail; }
  212.     
  213.         /* get the first item reference */
  214.     err = GetDragItemReferenceNumber(theDragRef, 1, &theItem);
  215.     if (err != noErr) goto bail;
  216.         
  217.         /* try to get a  HFSFlavor*/
  218.     theSize = sizeof(HFSFlavor);
  219.     err = GetFlavorData(theDragRef, theItem, flavorTypeHFS, &targetFile, &theSize, 0);
  220.     if (err != noErr) goto bail;
  221.     
  222.         /* display the located file*/
  223.     SetNewDisplay(&targetFile.fileSpec);
  224.     return noErr;
  225. bail:
  226.     return err;
  227. }
  228.  
  229.  
  230.  
  231.  
  232. /* SetNewDisplay is called to set the file or folder being displayed in the main window.
  233.     Here, structures are deallocated and an alias is saved referring to the file. 
  234.     SetNewDisplay is called from the drag receive handler and since it is not
  235.     safe to call "GetIconSuiteFromFinder()" from inside of the drag receive handler
  236.     (it uses apple events), the flag is used to defer that operation
  237.     until the next time ValidateFDPWindowDisplay.  ValidateFDPWindowDisplay is
  238.     called from the main loop.  If targetFile is NULL, then the display is cleared. */
  239. void SetNewDisplay(FSSpec *targetFile) {
  240.     SInt16 theLabel;
  241.     FSSpec mainPackageFile;
  242.         /* remove the old file */
  243.     if (gFileInDisplay) {
  244.         DisposeHandle((Handle) gFileAlias);
  245.         gFileAlias = NULL;
  246.         ReleaseIconRef(gIconRef);
  247.         gIconRef = NULL;
  248.         gFileInDisplay = false;
  249.         SetPort(gPackageWindow);
  250.         InvalRect(&gIconBox);
  251.     }
  252.         /* if there's no new file, we're done */
  253.     if (targetFile == NULL) goto bail;
  254.         /* create the new alias */
  255.     if (NewAliasMinimal(targetFile, &gFileAlias) != noErr) goto bail;
  256.         /* determine the kind of object we're displaying */
  257.     if (IdentifyPackage(targetFile, &mainPackageFile)) {
  258.         if (GetIconRefFromFile(&mainPackageFile, &gIconRef, &theLabel) != noErr) goto bail;
  259.         gFolderTypeSelection = kFolderIsPackage;
  260.     } else {
  261.         if (GetIconRefFromFile(targetFile, &gIconRef, &theLabel) != noErr) goto bail;
  262.         gFolderTypeSelection = kFolderIsFolder;
  263.     }
  264.         /* set up the controls */
  265.     SetControlValue(gPackageButton, (gFolderTypeSelection == kFolderIsPackage ? 1 : 0));
  266.     SetControlValue(gFolderButton, (gFolderTypeSelection == kFolderIsFolder ? 1 : 0));
  267.     HiliteControl(gPackageButton, (gPWActive ? 0 : 255));
  268.     HiliteControl(gFolderButton, (gPWActive ? 0 : 255));
  269.         /* update the window */
  270.     SetPort(gPackageWindow);
  271.     InvalRect(&gIconBox);
  272.         /* set the flag and return */
  273.     gFileInDisplay = true;
  274.     return;
  275. bail:
  276.     if (gFileAlias != NULL) DisposeHandle((Handle) gFileAlias);
  277.     if (gIconRef != NULL) ReleaseIconRef(gIconRef);
  278.     HiliteControl(gPackageButton, 255);
  279.     HiliteControl(gFolderButton, 255);
  280.     SetPort(gPackageWindow);
  281.     InvalRect(&gIconBox);
  282.     gFileInDisplay = false;
  283. }
  284.  
  285.  
  286.  
  287.  
  288. /* ActivatePackageWindow handles an activate event for the
  289.     package window. */
  290. void ActivatePackageWindow(WindowPtr target, Boolean activate) {
  291.     HiliteControl(gPackageButton, ((gPackageWindow == FrontWindow() && gFileInDisplay) ? 0 : 255));
  292.     HiliteControl(gFolderButton, ((gPackageWindow == FrontWindow() && gFileInDisplay) ? 0 : 255));
  293.     DrawDialog(gPackageWindow);
  294.     gPWActive = activate;
  295. }
  296.  
  297.  
  298.  
  299. /* PackageWindowUserItem draws the image in the drop box in the window.  If the window
  300.     is not the active window, then the image is drawn grayed out.  If appearance
  301.     is in use, then the drop box is drawn as a generic well. */
  302. static pascal void PackageWindowUserItem(WindowPtr theWindow, DialogItemIndex itemNo) {
  303.     RGBColor sForground, sBackground;
  304.     RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF}, rgbBlack = {0, 0, 0}, rgbGray = {0x7FFF, 0x7FFF, 0x7FFF};
  305.     FSSpec target;
  306.     ThemeDrawState themeDrawState;
  307.     Boolean wasChanged;
  308.         /* set up */
  309.     SetPort(theWindow);
  310.         /* set the colors we're using for drawing */
  311.     GetForeColor(&sForground);
  312.     GetBackColor(&sBackground);
  313.     RGBForeColor(&rgbBlack);
  314.     RGBBackColor(&rgbWhite);
  315.         /* draw the frame */
  316.     themeDrawState = (gPWActive && (theWindow == FrontWindow())) ? kThemeStateActive : kThemeStateInactive;
  317.     DrawThemeGenericWell(&gIconBox, themeDrawState,  true);
  318.         /* verify that we still have a file */
  319.     if (ResolveAlias(NULL, gFileAlias, &target, &wasChanged) != noErr) {
  320.         DisposeHandle((Handle) gFileAlias);
  321.         gFileAlias = NULL;
  322.         ReleaseIconRef(gIconRef);
  323.         gIconRef = NULL;
  324.         gFileInDisplay = false;
  325.     }
  326.         /* draw the file information */
  327.     if (gFileInDisplay) {
  328.         OSErr err;
  329.         short baseLine;
  330.         FontInfo fin;
  331.         Str255 name;
  332.             /* begin drawing */
  333.         TextFont(kFontIDGeneva); /* geneva */
  334.         TextSize(9);
  335.         GetFontInfo(&fin);
  336.             /* draw the icon image */
  337.         err = PlotIconRef(&gIconImage, kAlignNone, kTransformNone, kIconServicesNormalUsageFlag, gIconRef);
  338.             /* draw the file name */
  339.         baseLine = gIconImage.bottom + fin.ascent;
  340.         memcpy(name, target.name, target.name[0] + 1);
  341.         TruncString(gIconBox.right - gIconBox.left - 4, name,  truncEnd);
  342.         MoveTo((gIconBox.left + gIconBox.right - StringWidth(name))/2, baseLine);
  343.         DrawString(name);
  344.             /* end drawing */
  345.         TextFont(systemFont); /* back to the system font */
  346.         TextSize(12);
  347.     } else {
  348.         Rect rPic;
  349.         rPic = (**gSplashPict).picFrame;
  350.         OffsetRect(&rPic, -rPic.left, -rPic.top);
  351.         OffsetRect(&rPic, (gIconBox.left + gIconBox.right - rPic.right)/2, (gIconBox.top + gIconBox.bottom - rPic.bottom)/2);
  352.         DrawPicture(gSplashPict, &rPic);
  353.     }
  354.         /* gray the image if we're in the background */
  355.     if ( ! (gPWActive && (theWindow == FrontWindow())) ) {
  356.         GrayOutBox(&gIconBox);
  357.     }
  358.         /* restore previous colors */
  359.     RGBForeColor(&sForground);
  360.     RGBBackColor(&sBackground);
  361. }
  362.  
  363.  
  364.  
  365. static Boolean VerifyPackage(FSSpec *target) {
  366.     CInfoPBRec cat;
  367.     OSErr err;
  368.     long packageFolderDirID;
  369.     Str255 name, errstr;
  370.     FSSpec aliasFile, mainFile;
  371.     Boolean targetIsFolder, wasAliased;
  372.     long aliasCount;
  373.     
  374.         /* set up locals */
  375.     aliasCount = 0;
  376.     
  377.         /* make sure file sharing is turned off */
  378.     if ( FileSharingAppIsRunning() ) {
  379.         GetIndString(errstr, kMainStringList, kFileSharingOn);
  380.         ParamAlert(kPackageDidNotVerify, target->name, errstr);
  381.         return false;
  382.     }
  383.  
  384.         /* check the target's flags */
  385.     memset(&cat, 0, sizeof(cat));
  386.     cat.dirInfo.ioNamePtr = target->name;
  387.     cat.dirInfo.ioVRefNum = target->vRefNum;
  388.     cat.dirInfo.ioFDirIndex = 0;
  389.     cat.dirInfo.ioDrDirID = target->parID;
  390.     err = PBGetCatInfoSync(&cat);
  391.     if (err != noErr) return false;
  392.     if ((cat.dirInfo.ioFlAttrib & 16) == 0) {
  393.         GetIndString(errstr, kMainStringList, kNotAFolder);
  394.         ParamAlert(kPackageDidNotVerify, target->name, errstr);
  395.         return false;
  396.     }
  397.         /* if the bundle flag is set and we arrive here,
  398.         then we didn't recognize the package in the first
  399.         place.  That's an internal error. */
  400.     if ((cat.dirInfo.ioDrUsrWds.frFlags & kHasBundle) != 0) {
  401.         GetIndString(errstr, kMainStringList, kBundleAlreadySet);
  402.         ParamAlert(kPackageDidNotVerify, target->name, errstr);
  403.         return false;
  404.     }
  405.     
  406.         /* search for a top level alias file */
  407.     packageFolderDirID = cat.dirInfo.ioDrDirID;
  408.     memset(&cat, 0, sizeof(cat));
  409.     cat.dirInfo.ioNamePtr = name;
  410.     cat.dirInfo.ioVRefNum = target->vRefNum;
  411.     cat.dirInfo.ioFDirIndex = 1;
  412.     cat.dirInfo.ioDrDirID = packageFolderDirID;
  413.     while (PBGetCatInfoSync(&cat) == noErr) {
  414.         if (((cat.dirInfo.ioFlAttrib & 16) == 0) && ((cat.dirInfo.ioDrUsrWds.frFlags & kIsAlias) != 0)) {
  415.             aliasCount += 1;
  416.                 /* resolve the alias file */
  417.             err = FSMakeFSSpec(target->vRefNum, packageFolderDirID, name, &aliasFile);
  418.             if (err != noErr) return false;
  419.             mainFile = aliasFile;
  420.             err = ResolveAliasFile(&mainFile, false, &targetIsFolder, &wasAliased);
  421.             if (err != noErr) {
  422.                 GetIndString(errstr, kMainStringList, kBrokenAlias);
  423.                 ParamAlert(kPackageDidNotVerify, target->name, errstr);
  424.                 return false;
  425.             }
  426.             if (targetIsFolder) {
  427.                 GetIndString(errstr, kMainStringList, kAliasRefersToFolder);
  428.                 ParamAlert(kPackageDidNotVerify, target->name, errstr);
  429.                 return false;
  430.             }
  431.         }
  432.         cat.dirInfo.ioFDirIndex++;
  433.         cat.dirInfo.ioDrDirID = packageFolderDirID;
  434.     }
  435.         /* check the alias count */
  436.     if (aliasCount == 0) {
  437.         GetIndString(errstr, kMainStringList, kNoAliasPresent);
  438.         ParamAlert(kPackageDidNotVerify, target->name, errstr);
  439.         return false;
  440.     }
  441.     if (aliasCount > 1) {
  442.         GetIndString(errstr, kMainStringList, kMoreThanOneAlias);
  443.         ParamAlert(kPackageDidNotVerify, target->name, errstr);
  444.         return false;
  445.     }
  446.         /* make sure the alias and the target are in separate directories */
  447.     if ( mainFile.parID == aliasFile.parID ) {
  448.         GetIndString(errstr, kMainStringList, kInSameDirectory);
  449.         ParamAlert(kPackageDidNotVerify, target->name, errstr);
  450.         return false;
  451.     }
  452.         /* make sure the target is inside of the package directory */
  453.     if ( ! FSSpecIsInDirectory(&mainFile, target->vRefNum, packageFolderDirID) ) {
  454.         GetIndString(errstr, kMainStringList, kMainOutsideOfPackage);
  455.         ParamAlert(kPackageDidNotVerify, target->name, errstr);
  456.         return false;
  457.     }
  458.         /* all tests successful */
  459.     return true;
  460. }
  461.  
  462.  
  463.  
  464. static OSStatus FolderToPackage(FSSpec *packageDir) {
  465.     CInfoPBRec cat;
  466.     OSErr err;
  467.     FSSpec aliasFile, mainFile;
  468.     long packageFolderDirID;
  469.     Boolean foundAlias, targetIsFolder, wasAliased;
  470.     Str255 name;
  471.         /* set up locals */
  472.     foundAlias = false;
  473.         /* find out the folder's directory ID */
  474.     memset(&cat, 0, sizeof(cat));
  475.     cat.dirInfo.ioNamePtr = packageDir->name;
  476.     cat.dirInfo.ioVRefNum = packageDir->vRefNum;
  477.     cat.dirInfo.ioFDirIndex = 0;
  478.     cat.dirInfo.ioDrDirID = packageDir->parID;
  479.     err = PBGetCatInfoSync(&cat);
  480.     if (err != noErr) return err;
  481.     packageFolderDirID = cat.dirInfo.ioDrDirID;
  482.         /* search for a top level alias file */
  483.     memset(&cat, 0, sizeof(cat));
  484.     cat.dirInfo.ioNamePtr = name;
  485.     cat.dirInfo.ioVRefNum = packageDir->vRefNum;
  486.     cat.dirInfo.ioFDirIndex = 1;
  487.     cat.dirInfo.ioDrDirID = packageFolderDirID;
  488.     while (PBGetCatInfoSync(&cat) == noErr) {
  489.         if (((cat.dirInfo.ioFlAttrib & 16) == 0) && ((cat.dirInfo.ioDrUsrWds.frFlags & kIsAlias) != 0)) {
  490.                 /* resolve the alias file */
  491.             err = FSMakeFSSpec(packageDir->vRefNum, packageFolderDirID, name, &aliasFile);
  492.             if (err != noErr) return err;
  493.             mainFile = aliasFile;
  494.             err = ResolveAliasFile(&mainFile, false, &targetIsFolder, &wasAliased);
  495.             if (err != noErr) return err;
  496.             foundAlias = true;
  497.             break;
  498.         }
  499.         cat.dirInfo.ioFDirIndex++;
  500.         cat.dirInfo.ioDrDirID = packageFolderDirID;
  501.     }
  502.     if ( ! foundAlias) return paramErr;
  503.         /* update the alias file to a relative path */
  504.     err = UpdateRelativeAliasFile(&aliasFile, &mainFile);
  505.     if (err != noErr) return err;
  506.         /* set the package flag */
  507.     cat.dirInfo.ioNamePtr = packageDir->name;
  508.     cat.dirInfo.ioVRefNum = packageDir->vRefNum;
  509.     cat.dirInfo.ioFDirIndex = 0;
  510.     cat.dirInfo.ioDrDirID = packageDir->parID;
  511.     err = PBGetCatInfoSync(&cat);
  512.     if (err != noErr) return err;
  513.     cat.dirInfo.ioDrDirID = packageDir->parID;
  514.     cat.dirInfo.ioDrUsrWds.frFlags |= kHasBundle;
  515.     err = PBSetCatInfoSync(&cat);
  516.     if (err != noErr) return err;
  517.     return noErr;
  518. }
  519.  
  520.  
  521. static OSStatus PackageToFolder(FSSpec *target) {
  522.     CInfoPBRec cat;
  523.     OSErr err;
  524.     cat.dirInfo.ioNamePtr = target->name;
  525.     cat.dirInfo.ioVRefNum = target->vRefNum;
  526.     cat.dirInfo.ioFDirIndex = 0;
  527.     cat.dirInfo.ioDrDirID = target->parID;
  528.     err = PBGetCatInfoSync(&cat);
  529.     if (err != noErr) return err;
  530.     cat.dirInfo.ioDrDirID = target->parID;
  531.     cat.dirInfo.ioDrUsrWds.frFlags &= ~ kHasBundle;
  532.     err = PBSetCatInfoSync(&cat);
  533.     return err;
  534. }
  535.  
  536.  
  537.  
  538.  
  539.  
  540. /* HitPackageWindow is called when the dialog manager's DialogSelect indicates
  541.     that an item in the main finder drag pro window has been hit.  Here,
  542.     either we begin a drag, or we adjust the promise/regular hfs controls */
  543. void HitPackageWindow(DialogPtr theDialog, EventRecord *event, short itemNo) {
  544.     switch (itemNo) {
  545.         case kPackageUserItem:
  546.             break;
  547.             
  548.         case kFolderItem: /* turn it into a folder */
  549.             if (gFolderTypeSelection != kFolderIsFolder) {
  550.                 FSSpec target;
  551.                 Boolean wasChanged;
  552.                 if (ResolveAlias(NULL, gFileAlias, &target, &wasChanged) != noErr) {
  553.                     SetNewDisplay(NULL);
  554.                 } else {
  555.                     if (PackageToFolder(&target) == noErr) {
  556.                         SetNewDisplay(&target); /* update the view */
  557.                         ShowChangesInFinderWindow(target.vRefNum, target.parID);
  558.                     }
  559.                 }
  560.             }
  561.             break;
  562.             
  563.         case kPackageItem: /* turn it into a package */
  564.             if (gFolderTypeSelection != kFolderIsPackage) {
  565.                 FSSpec target;
  566.                 Boolean wasChanged;
  567.                 if (ResolveAlias(NULL, gFileAlias, &target, &wasChanged) != noErr) {
  568.                     SetNewDisplay(NULL);
  569.                 } else {
  570.                     if (VerifyPackage(&target)) {
  571.                         OSStatus err;
  572.                         err = FolderToPackage(&target);
  573.                         if (err != noErr) {
  574.                             Str255 errStr;
  575.                             NumToString(err, errStr);
  576.                             ParamAlert(kFailedToCreatePackage, errStr, target.name);
  577.                         } else {
  578.                             SetNewDisplay(&target); /* update the view */
  579.                             ShowChangesInFinderWindow(target.vRefNum, target.parID);
  580.                         }
  581.                     }
  582.                 }
  583.             }
  584.             break;
  585.     }
  586. }
  587.  
  588.  
  589.  
  590. /* CreatePackageWindow creates the package window.  If it cannot be
  591.     created, then an error is returned. */
  592. OSStatus CreatePackageWindow(void) {
  593.     OSErr err;
  594.     Boolean installedTracker, installedReceiver;
  595.     short itemt;
  596.     Rect itemb;
  597.     Handle itemh;
  598.     DialogPtr dialog;
  599.     long itemSize;
  600.     Point where;
  601.     
  602.         /* set up locals for recovery */
  603.     dialog = NULL;
  604.     installedTracker = installedReceiver = false;
  605.     
  606.         /* get other resources */
  607.     gSplashPict = GetPicture(kSpashPictResource);
  608.     if (gSplashPict == NULL) { err = resNotFound; goto bail; }
  609.         /* create the dialog */
  610.     dialog = GetNewDialog(kPackageDialogResource, NULL, (WindowPtr) (-1));    
  611.     if (dialog == NULL) { err = memFullErr; goto bail; }
  612.     
  613.         /* grab and set up our dialog items */
  614.     GetDialogItem(dialog, kPackageUserItem, &itemt, (Handle*) &itemh, &gIconBox);
  615.     myUserItem = NewUserItemProc(PackageWindowUserItem);
  616.     if (myUserItem == NULL) { err = memFullErr; goto bail; }    
  617.     SetDialogItem(dialog, kPackageUserItem, userItem, (Handle) myUserItem, &gIconBox);
  618.     GetDialogItem(dialog, kFolderItem, &itemt, (Handle*) &gFolderButton, &itemb);
  619.     GetDialogItem(dialog, kPackageItem, &itemt, (Handle*) &gPackageButton, &itemb);
  620.         
  621.         /* set initial control values */
  622.     SetControlValue(gPackageButton, (gFolderTypeSelection == kFolderIsPackage ? 1 : 0));
  623.     SetControlValue(gFolderButton, (gFolderTypeSelection == kFolderIsFolder ? 1 : 0));
  624.     HiliteControl(gPackageButton, 255);
  625.     HiliteControl(gFolderButton, 255);
  626.  
  627.         /* calculate the drawn icon's boundary */
  628.     SetRect(&gIconImage, 0, 0, 32, 32);
  629.     OffsetRect(&gIconImage, (gIconBox.right + gIconBox.left - 32) / 2, gIconBox.top + 32);
  630.  
  631.         /* install the drag handlers */
  632.     gMainTrackingHandler = NewDragTrackingHandlerProc(MyDragTrackingHandler);
  633.     if (gMainTrackingHandler == NULL) { err = memFullErr; goto bail; }
  634.     err = InstallTrackingHandler(gMainTrackingHandler, dialog, NULL);
  635.     if (err != noErr) { err = memFullErr; goto bail; }
  636.     installedTracker = true;
  637.  
  638.     gMainReceiveHandler = NewDragReceiveHandlerProc(MyDragReceiveHandler);
  639.     if (gMainReceiveHandler == NULL) { err = memFullErr; goto bail; }
  640.     err = InstallReceiveHandler(gMainReceiveHandler, dialog, NULL);
  641.     if (err != noErr) { err = memFullErr; goto bail; }
  642.     installedReceiver = true;
  643.  
  644.         /* position the window, if necessary */
  645.     if (GetCollectionItem(GetCollectedPreferences(),  'QDPt', 1, (itemSize = sizeof(where), &itemSize),  &where) == noErr) {
  646.         MoveWindow(dialog, where.h, where.v, true);
  647.     }
  648.         /* done, window complete */
  649.     ShowWindow(dialog);
  650.     gPackageWindow = dialog;
  651.     return noErr;
  652.  
  653. bail:
  654.     if (installedReceiver)
  655.         RemoveReceiveHandler(gMainReceiveHandler, dialog);
  656.     if (installedTracker)
  657.         RemoveTrackingHandler(gMainTrackingHandler, dialog);
  658.     if (dialog != NULL) DisposeDialog(dialog);
  659.     return err;
  660. }
  661.  
  662. /* ClosePackageWindow closes the package window and disposes of
  663.     any structures allocated when it was opened. */
  664. void ClosePackageWindow(void) {
  665.     Point where;
  666.     SetPort(gPackageWindow);
  667.     where = * (Point*) &gPackageWindow->portRect;
  668.     LocalToGlobal(&where);
  669.     AddCollectionItem(GetCollectedPreferences(), 'QDPt', 1, sizeof(where), &where);
  670.     SetNewDisplay(NULL);
  671.     DisposeDialog(gPackageWindow);
  672. }
  673.  
  674.